import { NativeEventEmitter, NativeModules, Platform } from 'react-native';

const LINKING_ERROR =
  `The package 'react-native-speech-engine' doesn't seem to be linked. Make sure: \n\n` +
  Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
  '- You rebuilt the app after installing the package\n' +
  '- You are not using Expo Go\n';

// @ts-expect-error
const isTurboModuleEnabled = global.__turboModuleProxy != null;

const SpeechEngineModule = isTurboModuleEnabled
  ? require('./NativeSpeechEngine').default
  : NativeModules.SpeechEngine;

const SpeechEngine = SpeechEngineModule
  ? SpeechEngineModule
  : new Proxy(
      {},
      {
        get() {
          throw new Error(LINKING_ERROR);
        },
      }
    );

const eventEmitter = new NativeEventEmitter(SpeechEngine);

export interface SpeechRecognitionOptions {
  locale?: string;
  maxResults?: number;
  partialResults?: boolean;
}

export interface TextToSpeechOptions {
  language?: string;
  pitch?: number;
  rate?: number;
  volume?: number;
}

export interface SpeechRecognitionResult {
  transcript: string;
  confidence: number;
  isFinal: boolean;
}

export interface SpeechRecognitionError {
  code: string;
  message: string;
}

class SpeechEngineClass {
  private speechRecognitionListeners: { [key: string]: any } = {};
  private textToSpeechListeners: { [key: string]: any } = {};

  // Speech Recognition Methods
  async startSpeechRecognition(options: SpeechRecognitionOptions = {}): Promise<void> {
    const { locale = 'en-US' } = options;
    return SpeechEngine.startSpeechRecognition(locale);
  }

  async stopSpeechRecognition(): Promise<string> {
    return SpeechEngine.stopSpeechRecognition();
  }

  async cancelSpeechRecognition(): Promise<void> {
    return SpeechEngine.cancelSpeechRecognition();
  }

  async isSpeechRecognitionAvailable(): Promise<boolean> {
    return SpeechEngine.isSpeechRecognitionAvailable();
  }

  // Text to Speech Methods
  async speak(text: string, options: TextToSpeechOptions = {}): Promise<void> {
    const {
      language = 'en-US',
      pitch = 1.0,
      rate = 1.0,
      volume = 1.0,
    } = options;
    
    return SpeechEngine.speak(text, {
      language,
      pitch,
      rate,
      volume,
    });
  }

  async stop(): Promise<void> {
    return SpeechEngine.stop();
  }

  async pause(): Promise<void> {
    return SpeechEngine.pause();
  }

  async resume(): Promise<void> {
    return SpeechEngine.resume();
  }

  async isSpeaking(): Promise<boolean> {
    return SpeechEngine.isSpeaking();
  }

  // Event Listeners for Speech Recognition
  onSpeechRecognitionResults(callback: (results: SpeechRecognitionResult[]) => void) {
    const listener = eventEmitter.addListener('onSpeechRecognitionResults', callback);
    this.speechRecognitionListeners['onSpeechRecognitionResults'] = listener;
    return listener;
  }

  onSpeechRecognitionError(callback: (error: SpeechRecognitionError) => void) {
    const listener = eventEmitter.addListener('onSpeechRecognitionError', callback);
    this.speechRecognitionListeners['onSpeechRecognitionError'] = listener;
    return listener;
  }

  onSpeechRecognitionStart(callback: () => void) {
    const listener = eventEmitter.addListener('onSpeechRecognitionStart', callback);
    this.speechRecognitionListeners['onSpeechRecognitionStart'] = listener;
    return listener;
  }

  onSpeechRecognitionEnd(callback: () => void) {
    const listener = eventEmitter.addListener('onSpeechRecognitionEnd', callback);
    this.speechRecognitionListeners['onSpeechRecognitionEnd'] = listener;
    return listener;
  }

  // Event Listeners for Text to Speech
  onTextToSpeechStart(callback: () => void) {
    const listener = eventEmitter.addListener('onTextToSpeechStart', callback);
    this.textToSpeechListeners['onTextToSpeechStart'] = listener;
    return listener;
  }

  onTextToSpeechFinish(callback: () => void) {
    const listener = eventEmitter.addListener('onTextToSpeechFinish', callback);
    this.textToSpeechListeners['onTextToSpeechFinish'] = listener;
    return listener;
  }

  onTextToSpeechError(callback: (error: string) => void) {
    const listener = eventEmitter.addListener('onTextToSpeechError', callback);
    this.textToSpeechListeners['onTextToSpeechError'] = listener;
    return listener;
  }

  // Cleanup methods
  removeAllSpeechRecognitionListeners() {
    Object.values(this.speechRecognitionListeners).forEach((listener: any) => {
      listener.remove();
    });
    this.speechRecognitionListeners = {};
  }

  removeAllTextToSpeechListeners() {
    Object.values(this.textToSpeechListeners).forEach((listener: any) => {
      listener.remove();
    });
    this.textToSpeechListeners = {};
  }

  removeAllListeners() {
    this.removeAllSpeechRecognitionListeners();
    this.removeAllTextToSpeechListeners();
  }
}

export default new SpeechEngineClass();
